package com.scd.jmeter.rmi.server;

import com.scd.jmeter.rmi.common.RemoteJMeterEngine;
import com.scd.jmeter.rmi.common.RmiUtils;
import com.scd.jmeter.rmi.common.TestPlan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.net.InetAddress;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.ServerNotActiveException;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;

public class RemoteJMeterEngineImpl extends UnicastRemoteObject implements RemoteJMeterEngine {
    private static final Logger log = LoggerFactory.getLogger(RemoteJMeterEngineImpl.class);

    /**
     * RMI Registry port
     */
    private final int rmiRegistryPort;

    private static final boolean CREATE_SERVER = true;
//            JMeterUtils.getPropDefault("server.rmi.create", true); // $NON-NLS-1$


    private RemoteJMeterEngineImpl(int localPort, int rmiRegistryPort) throws RemoteException {
        // Create this object using the specified port (0 means anonymous)
        super(localPort, RmiUtils.createClientSocketFactory(), RmiUtils.createServerSocketFactory());
        this.rmiRegistryPort = rmiRegistryPort;
        System.out.println("Created remote object: "+this.getRef().remoteToString());
    }

    public static void startServer(int rmiRegistryPort) throws RemoteException {
        RemoteJMeterEngineImpl engine =
                new RemoteJMeterEngineImpl(
                        RemoteMain.DEFAULT_LOCAL_PORT,
                        rmiRegistryPort);
        engine.init();
    }

    private void init() throws RemoteException {
//        log.info("Starting backing engine on {}", this.rmiRegistryPort);
        InetAddress localHost = RmiUtils.getRmiHost();
        if (localHost.isSiteLocalAddress()){
            // should perhaps be log.warn, but this causes the client-server test to fail
            log.info("IP address is a site-local address; this may cause problems with remote access.\n"
                    + "\tCan be overridden by defining the system property 'java.rmi.server.hostname' - see jmeter-server script file");
        }
        log.debug("This = {}", this);
        Registry reg = null;
        if (CREATE_SERVER){
            log.info("Creating RMI registry (server.rmi.create=true)");
            try {
                reg = LocateRegistry.createRegistry(this.rmiRegistryPort,
                        RmiUtils.createClientSocketFactory(),
                        RmiUtils.createServerSocketFactory());
                log.debug("Created registry: {}", reg);
            } catch (RemoteException e){
                String msg="Problem creating registry: "+e;
                log.warn(msg);
                System.err.println(msg);
                System.err.println("Continuing...");
            }
        }
        try {
            if (reg == null) {
                log.debug("Locating registry");
                reg = LocateRegistry.getRegistry(
                        RmiUtils.getRmiHost().getHostName(),
                        this.rmiRegistryPort,
                        RmiUtils.createClientSocketFactory());
            }
            log.debug("About to rebind registry: {}", reg);
            reg.rebind(RmiUtils.JMETER_ENGINE_RMI_NAME, this);
            log.info("Bound to RMI registry on port {}", this.rmiRegistryPort);
        } catch (Exception ex) {
            log.error("rmiregistry needs to be running to start JMeter in server mode. {}", ex.toString());
            // Throw an Exception to ensure caller knows ...
            throw new RemoteException("Cannot start. See server log file.", ex);
        }
    }

    @Override
    public void rconfigure(TestPlan testPlan, String host, File jmxBase, String scriptName) throws RemoteException {
        log.info("Creating JMeter engine on host {} base '{}'", host, jmxBase);
        try {
            if (log.isInfoEnabled()) {
                log.info("Remote client host: {}", getClientHost());
            }
        } catch (ServerNotActiveException e) {
            // ignored
        }
//        synchronized(LOCK) { // close window where another remote client might jump in
//            if (backingEngine != null && backingEngine.isActive()) {
//                log.warn("Engine is busy - cannot create JMeter engine");
//                throw new IllegalStateException("Engine is busy - please try later");
//            }
//            ownerThread = Thread.currentThread();
//            JMeterUtils.setProperty(JMeterUtils.THREAD_GROUP_DISTRIBUTED_PREFIX_PROPERTY_NAME, hostAndPort);
//            backingEngine = new StandardJMeterEngine(hostAndPort);
//            backingEngine.configure(testTree); // sets active = true
//        }
//        FileServer.getFileServer().setScriptName(scriptName);
//        FileServer.getFileServer().setBase(jmxBase);
        log.info("rconfigure test plan {}", testPlan);
    }

    @Override
    public void rrunTest() {
        log.info("Running test");
    }

    @Override
    public void rreset() throws RemoteException {
        log.info("Reset");
    }

    @Override
    public void rstopTest(boolean now) throws RemoteException {
        if (now) {
            log.info("Stopping test ...");
        } else {
            log.info("Shutting test ...");
        }
        log.info("... stopped");
    }

    /*
     * Called by:
     * - ClientJMeterEngine.exe() which is called on remoteStop
     */
    @Override
    public void rexit() throws RemoteException {
        log.info("Exiting");
        log.info("Unbound from registry");
    }

    @Override
    @SuppressWarnings("NonApiType")
    public void rsetProperties(HashMap<String, String> map) throws RemoteException { // NOSONAR
        log.info("rsetProperties");
    }

}
